<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			* {
				margin: 0;
				padding: 0;
			}

			div {
				background-color: #f00;
				display: flex;
			}

			p {
				background-color: pink;
			}

			img {
				vertical-align: middle;
			}
		</style>
	</head>
	<body>

		<div>
			<p>1</p>
			<p>2</p>
			<p><img src="./微信图片_20230814143730.png" alt="" height="100"></p>
			<p>4</p>
			<p>5</p>
			<p>6</p>
			<p>7</p>
			<p>8</p>
		</div>
		<!-- 
		 setup 
		 
		 
		 一,父子组件通信
			1父传子
			父组件 
			<SonPage ref="son" :obj='obj'></SonPage>
			子组件
			import { defineProps } from 'vue';
			const props = defineProps({
				obj: {
					type: Object,
					default: () => {}
				}
			});
			
			2.子传父		
			 父组件
			  <SonPage ref="son" :obj='obj' @toFather='toFather'></SonPage>
			  //js代码
			  const toFather=res=>{
			  	console.log('接受到了子组件的数据',res);
			  }
			 子组件
			 <template>
			 	<input type="text" v-model="val">
			 	<button @click="fn">子传父</button>
			 </template>
			 //js代码
			 const val = ref('')
			 const emits = defineEmits(['toFather'])
			 const fn = ()=>{
			 	emits('toFather',val.value)
			 }
			
			3. v-model:value = 'data'
			
			父组件 
			<SonPage ref="son" v-model:obj='obj'></SonPage>
			//等同于  <SonPage ref="son" :obj='obj' @update:obj='obj=$event'></SonPage>
			//注:这里只能使用ref数据 不能是reactive
			let obj = ref({
			  name:'张三',
			  age:18
			})
			
			子组件
			<button @click="fn">子传父</button>
			
			import { defineProps,defineEmits } from 'vue';
			const props = defineProps({
				obj: {
					type: Object,
					default: () => {}
				}
			});
			const emits = defineEmits(['update:obj'])
			const fn = ()=>{
				emits('update:obj',{name:val.value,age:99})
				val.value = ''
			}
			
			4.refs 方式
			
			父组件   
			<ul>
				<li v-for="i in children?.list" :key="i">{{i}}</li>
			</ul>
			<SonPage ref="children"></SonPage>
			import {ref} from 'vue'
			//定义一个变量  为  ref绑定的数据  注意 使用的时候  .value
			const children = ref(null)
			
			子组件 
			<input type="text" v-model="val">
			<button @click="fn">add子传父</button>
			
			import {ref,defineExpose} from 'vue'
			const list =ref(['aaa','bbb','ccc'])
			const val = ref('');
			const fn = ()=>{
				console.log(val.value);
				list.value.push(val.value)
				val.value=''
			}
			defineExpose({list})
			
			子组件里面的 属性方法 需要通过 defineExpose 暴露出来才能使用  数据存在   children.value 里面
		二,隔代组件通信
		inject provide
		
		父组件 
		<input type="text" v-model="val">
				<button @click="fn">add子传父</button>
		<SonPage ref="children"></SonPage>
		
		import SonPage from './SonPage.vue'
		import {ref,provide} from 'vue'
		const list =ref(['aaa','bbb','ccc'])
		const val = ref('');
		const fn = ()=>{
			console.log(val.value);
			list.value.push(val.value)
			val.value=''
		}
		provide('list',list.value)
		
		子组件
		<div class="son">
			<p v-for="i in list" :key="i">{{i}}</p>
		</div>
		import {inject} from 'vue'
		const list = inject('list')
		
		三.vuex   
			使用方式基本相同 
			
			在html使用  $store
			
			在 setup 里面   
			const store = useStore();
			console.log(store);
			
			注意 const store = useStore(); 必须在 setup 里面使用 不能写在 setup里面的函数里面
			
		四,vue3 不推荐使用 vuex 更多的使用  Pinia
		https://zhuanlan.zhihu.com/p/519634541
			
			基于vue3 的 组合式api  需要一个状态管理器  迎合 vue3的 组合式api
			并且vuex 是有很多问题  层级太深 体量太大  对ts使用 不方便
			vuex4   pinia ==> vuex5
			
			Pinia 特点   
				① 支持 vue2  vue3
				② 支持 vue  devtool
				③ 支持插件 功能扩展
				④ 更好的支持 ts 基本不需要做配置
				⑤  比vuex使用更简单
		如何使用C
			
			pinia 核心概念 比较vuex 只剩下 三个   state  getters  actions(同步异步都支持)
			
			① cnpm i pinia 
			
			②  再main.js 里面 使用 
				import { createPinia } from 'pinia'
				createApp(App).use(createPinia()).mount('#app')
			
			③ 在src文件夹 下面 创建 store目录 里面创建 一个 index.js文件 写入代码
				1.
				import {
					defineStore
				} from "pinia";
				//参数1：定义一个仓库的唯一id名，Pinia会将所有的容器挂载到根容器；参数2：选项对象
				export const useMainStore = defineStore('main', {
					state: () => { //state必须是函数，是避免在服务端渲染时的交叉请求导致的状态数据污染；必须是箭头函数，为了更好的TS类型推导
						return {
							count: 10,
							name: 'wl',
							arr: [1, 2, 3],
						}
					},
					getters: {
						//函数接受一个可选参数:state
						count10(state) {
							return state.count + 10
						}
						/*count10():number{   //在TS文件下，getters使用了this,则必须指定类型，否则会导致推导错误
						  return this.count += 12
						}*/
					},
					actions: {
						changeState(num, str) { //不要使用箭头函数定义action,因为箭头函数绑定外部this
							this.count += num
							this.name += str
							this.arr.push(5)
							// this.$patch({})或this.$patch(state=>{})    //还可通过$patch修改state的数据
						}
					}
				})
				2.
				import {defineStore} from "pinia";
				import {ref,computed} from 'vue'
				//参数1：定义一个仓库的唯一id名，Pinia会将所有的容器挂载到根容器；参数2：选项对象
				export const useMainStore =  defineStore('main',()=>{
					const count = ref(1)
					const count10 = computed(()=>{
						return count.value*10
					})
					function changeCount(){
						count.value++
					}
					return {
						count,count10,changeCount
					}
				})
				
			④ 使用 
			  1. 再组件里面使用 
					第一种用法
				  import { useMainStore } from '@/store/index.js';
				  const mainStore = useMainStore()
				  <div class="piana">
					<h2>piana</h2>
					<p>count{{ mainStore.count }}---name{{ mainStore.name }}----arr:{{ mainStore.arr }}</p>
					<button @click="changePiana">修改piana数据</button>
				  </div>
					第二种用法
					
					import { useMainStore } from '@/store/index.js';
					import { storeToRefs } from 'pinia';
					const { count, name, arr } = storeToRefs(mainStore);
					const mainStore = useMainStore()
					<div class="piana">
						<h2>piana</h2>
						<p>count{{ count }}---name{{ name }}----arr:{{ arr }}</p>
						<button @click="changePiana">修改piana数据</button>
					</div>
		
			  2.修改状态
			   function changeNum() {
					mainStore.count++            //法1
					mainStore.$patch({           //法2：修改多个数据，用$patch
						count:mainStore.count + 1,
						name:mainStore.name + '!',
						arr:[...mainStore.arr,4]
					})         
					mainStore.$patch(state=>{          //法3：$patch函数会批量更新
						state.count++
						state.name += '~~'
						state.arr.push(5)
					})
					mainStore.changeState(10,'hello')   //法4：逻辑比较多时使用actions
				}
		 -->
	</body>
</html>